import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.Font;

// This class handles the race panel.  Horses and track background are implemented here.
public class RacePanel extends JPanel implements Runnable {

	/**
	 * Prevents warning message
	 */
	private static final long serialVersionUID = 1L;

	private Image track1, horses[], userPanelBackground, finishLine1,
			finishLine2, finishLine3, finishLine4, finishLine5, clock,
			startShoe, addUser, win1, win2, win3, win4, win5, win6, trophy,
			info;
	private Thread animatorThread;
	private String imageLocation, userName, userID;
	private ArrayList<String> idList = new ArrayList<String>(),
			computerHorse = new ArrayList<String>();
	private int rands[], maxPlayers, bgW, bgH, frameNumber, delay, speed, fps,
			numberOfPlayers, timeCount, lucky, minorLucky, energyHorse,
			lastSecond, win, rNum, jM;
	private JPanel userPanels[] = new JPanel[6],
			userPosition[] = new JPanel[6], winnerPanel, infoPanel,
			trophyPanel, timerPanel, timerPanel2, background = new JPanel(),
			timerTitle = new JPanel(), timerTitle2 = new JPanel(),
			addingUsers = new JPanel();
	private JLabel user[] = new JLabel[6], position, timerLabel, timerLabel2,
			wBust[] = new JLabel[6];
	private boolean waiting, newGame, jeffMagic;
	private Color jockeyColor[] = { new Color(215, 115, 175, 255),
			new Color(77, 162, 209, 255), new Color(0, 195, 129, 255),
			new Color(166, 167, 208, 255), new Color(255, 170, 95, 255),
			new Color(255, 80, 83, 255) };
	private Random randomGenerator2 = new Random();

	private getUserFromSite person = new getUserFromSite();

	/**
	 * Constructor initializes grid for user panel
	 * 
	 * @throws Exception
	 */
	public RacePanel(int players, String imgLocation) throws Exception {
		// set size of track panel
		this.bgW = 1150;
		this.bgH = 400;
		this.setSize(bgW, bgH);
		this.setLocation(70, 170);
		this.maxPlayers = players; // initialize maxPlayers
		this.imageLocation = imgLocation; // initialize imageLocaton

		// Create random array and horses array
		rands = new int[this.maxPlayers];
		horses = new Image[this.maxPlayers];

		track1 = ImageIO.read(new File("imgFiles/Ftrack2b(2).jpg"));
		userPanelBackground = ImageIO
				.read(new File("imgFiles/game_screen1.jpg"));
		finishLine1 = ImageIO.read(new File("imgFiles/finish5.jpg"));
		finishLine2 = ImageIO.read(new File("imgFiles/finish4.jpg"));
		finishLine3 = ImageIO.read(new File("imgFiles/finish3.jpg"));
		finishLine4 = ImageIO.read(new File("imgFiles/finish2.jpg"));
		finishLine5 = ImageIO.read(new File("imgFiles/finish1.jpg"));
		clock = ImageIO.read(new File("imgFiles/clock.jpg"));
		startShoe = ImageIO.read(new File("imgFiles/goldShoe.jpg"));
		addUser = ImageIO.read(new File("imgFiles/addUsers.jpg"));
		win1 = ImageIO.read(new File("imgFiles/Winner 1.gif"));
		win2 = ImageIO.read(new File("imgFiles/Winner 2.gif"));
		win3 = ImageIO.read(new File("imgFiles/Winner 3.gif"));
		win4 = ImageIO.read(new File("imgFiles/Winner 4.gif"));
		win5 = ImageIO.read(new File("imgFiles/Winner 5.gif"));
		win6 = ImageIO.read(new File("imgFiles/Winner 6.gif"));
		trophy = ImageIO.read(new File("imgFiles/trophy.jpg"));
		info = ImageIO.read(new File("imgFiles/winner.jpg"));

		// computer players added...
		computerHorse.add("Seabiscuit");
		computerHorse.add("War Admiral");
		computerHorse.add("Eclipse");
		computerHorse.add("Cigar");
		computerHorse.add("Storm Cat");
		computerHorse.add("Jeff-Magic");

		String loc = "";

		for (int i = 0; i < this.maxPlayers; i++) {
			loc = this.imageLocation + (i + 1) + ".png";
			horses[i] = ImageIO.read(new File(loc));
			user[i] = new JLabel(" ");
			userPanels[i] = new JPanel();
			userPosition[i] = new JPanel();
			winnerPanel = new JPanel();
			infoPanel = new JPanel();
			trophyPanel = new JPanel();
		}

		// How many milliseconds between frames?
		fps = 30;
		delay = (fps > 0) ? (2000 / fps) : 20;
		speed = 5; // speed controls how fast the horses move across the track

		resetGame();
		start();
	}

	public void start() {
		if (animatorThread == null) {
			animatorThread = new Thread(this);
			animatorThread.start();
			playS();
		}
	}

	public void resetGame() throws Exception {

		if (!this.idList.isEmpty()) {
			try {
				person.userWon(this.idList.get(win - 1));
				System.out.println("WINNING ID IS: " + idList.get(win - 1)
						+ "\n\n");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		for (int i = 0, j = 625, k = 660; i < this.maxPlayers; i++, k += 33) {
			if (i > 2) {
				userPanels[i].setLocation(j + 100, k);
				userPosition[i].setLocation(j + 45, k);
			}
			if (i < 3) {
				userPanels[i].setLocation(j - 300, k);
				userPosition[i].setLocation(j - 355, k);
			}
			if (i == 2)
				k -= 99;
		}

		this.numberOfPlayers = 0;
		this.frameNumber = 0; // reset frame number
		this.waiting = false;
		this.newGame = true;
		this.timeCount = 10;
		this.idList.clear();
		this.winnerPanel.removeAll();
		this.computerHorse.clear();
		this.rNum = 6;
		addingUsers.setVisible(false);
		jeffMagic = false;

		for (int i = 0; i < this.maxPlayers; i++) {
			this.userPanels[i].setVisible(true);
			this.userPosition[i].setVisible(true);
		}

		winnerPanel.setVisible(false);
		infoPanel.setVisible(false);
		timerTitle.setVisible(false);
		trophyPanel.setVisible(false);

		computerHorse.add("Seabiscuit");
		computerHorse.add("War Admiral");
		computerHorse.add("Eclipse");
		computerHorse.add("Cigar");
		computerHorse.add("Storm Cat");
		computerHorse.add("Jeff-Magic");

		Random randomGenerator = new Random();
		// generating random numbers
		this.lucky = randomGenerator.nextInt(this.maxPlayers * 3);
		this.lastSecond = randomGenerator.nextInt(this.maxPlayers * 6);
		this.minorLucky = randomGenerator.nextInt(this.maxPlayers * 3);
		this.energyHorse = randomGenerator.nextInt(this.maxPlayers * 3);

		System.out.println("ENERGYHORSE = " + energyHorse + ", "
				+ "minorLucky = " + minorLucky + ", " + "MAJORLUCKY = " + lucky
				+ ", " + "lastSecond = " + lastSecond);

		// get user from site
		while (this.numberOfPlayers < this.maxPlayers) {
			this.userID = this.person.getUserID(); // possible user advantage
													// mod to add in

			for (int k = 0; this.userID.equals("") && k < 6; k++) {
				Thread.sleep(10);
				System.out.println("NO ONE HERE!, k = " + k);
				person.getUserID();
			}

			this.idList.add(this.userID);

			System.out.println(this.userID);

			int cHorse;

			if (this.userID.equals("")) {
				cHorse = randomGenerator2.nextInt(rNum);
				userName = computerHorse.get(cHorse);
				computerHorse.remove(cHorse);
				rNum--;
			} else {
				userName = person.getUserName();
			}
			rands[numberOfPlayers] = 0;
			userPanels[numberOfPlayers]
					.setBackground(this.jockeyColor[this.numberOfPlayers]);
			user[numberOfPlayers].setText(this.userName);

			if (this.userName.equals("Jeff-Magic")) {
				jeffMagic = true;
				jM = numberOfPlayers;
			}

			user[numberOfPlayers].setFont(new Font("", Font.BOLD, 18));
			userPosition[numberOfPlayers]
					.setBackground(this.jockeyColor[this.numberOfPlayers]);

			numberOfPlayers++;
		}
		
//		if(jeffMagic) {					// 'Problem?' code.  Not important, just for fun...  (doesn't work right now). 
//			for(int j = 0; j < this.maxPlayers; j++)
//				if(j == jM)
//					horses[jM] = ImageIO.read(new File("imgFiles/T" + (j + 1) + ".jpg"));
//		}

	
	}

	public void stop() {
		animatorThread = null;
		horses = null;
		// track1 = null;
		userPanelBackground = null;
	}

	public void run() {
		racing();
	}

	private void racing() {
		// Remember the starting time
		long startTime = System.currentTimeMillis();

		while (Thread.currentThread() == animatorThread) {
			// Display the next frame of animation.
			repaint();

			// Delay depending on how far we are behind.
			try {
				startTime += delay;
				Thread.sleep(Math.max(0, startTime - System.currentTimeMillis()));
			} catch (InterruptedException e) {
				break;
			}
			if (!this.waiting && !this.newGame)
				frameNumber++;
		}
	}

	public Component createUserPositions(int i, int x, int y) throws Exception {
		// Create user postions panels (1 - 6) numbering (lines up w/ players)
		userPosition[i].setSize(50, 30);

		if (i > 2)
			userPosition[i].setLocation(x + 45, y);
		if (i < 3)
			userPosition[i].setLocation(x - 350, y);

		userPosition[i].setBackground(this.jockeyColor[i]);
		userPosition[i].setVisible(true);

		// fill in user position panels
		position = new JLabel("" + (i + 1));
		position.setFont(new Font("Serif", Font.BOLD, 23));
		userPosition[i].add(position);
		userPosition[i].setVisible(true);
		
		return userPosition[i];
	}

	public Component createUserPanelBackground() {

		background.setSize(1280, 810);
		background.setLocation(0, 0);

		JLabel picLabel = new JLabel(new ImageIcon(userPanelBackground));
		background.add(picLabel);
		background.setVisible(true);

		return background;
	}

	public Component createUserPanels(int i, int x, int y) throws Exception {

		// Create user panel(s) (users are entered here after being scanned into
		// race)
		userPanels[i].setSize(300, 30);

		if (i > 2)
			userPanels[i].setLocation(x + 100, y);
		if (i < 3)
			userPanels[i].setLocation(x - 295, y);

		userPanels[i].setBackground(this.jockeyColor[i]);
		userPanels[i].setVisible(true);

		user[i].setFont(new Font("Serif", Font.BOLD, 23));

		
		userPanels[i].add(user[i]);
		userPanels[i].setVisible(true);

		return userPanels[i];
	}

	public Component createWinnerPanel() {

		// Create winner panel (don't make visible until winner is declared)
		winnerPanel.setSize(140, 140);
		winnerPanel.setBackground(Color.white);

		wBust[0] = new JLabel(new ImageIcon(win1));
		wBust[1] = new JLabel(new ImageIcon(win2));
		wBust[2] = new JLabel(new ImageIcon(win3));
		wBust[3] = new JLabel(new ImageIcon(win4));
		wBust[4] = new JLabel(new ImageIcon(win5));
		wBust[5] = new JLabel(new ImageIcon(win6));

		winnerPanel.setVisible(false);

		return winnerPanel;
	}

	public Component createTrophyPanel() {

		trophyPanel.setSize(100, 140);
		trophyPanel.setBackground(Color.white);

		JLabel picLabel = new JLabel(new ImageIcon(trophy));
		trophyPanel.add(picLabel);

		trophyPanel.setVisible(false);

		return trophyPanel;
	}

	public Component createWinnerInfoPanel() {

		infoPanel.setSize(300, 120);
		infoPanel.setBackground(Color.white);

		JLabel picLabel = new JLabel(new ImageIcon(info));
		infoPanel.add(picLabel);

		infoPanel.setVisible(false);

		return infoPanel;
	}

	public Component createTimerTitle() {

		timerTitle.setSize(154, 145);
		timerTitle.setLocation(1097, 627);
		timerTitle.setBackground(Color.white);

		JLabel picLabel = new JLabel(new ImageIcon(clock));
		timerTitle.add(picLabel);

		timerTitle.setVisible(false);

		return timerTitle;
	}

	public Component createTimerPanel() {

		// Create timer panel (don't make visible until winner is declared)
		timerPanel = new JPanel();
		timerLabel = new JLabel();
		timerPanel.setSize(70, 60);
		timerPanel.setLocation(1158, 680);
		timerPanel.setBackground(new Color(254, 134, 107, 255));
		timerLabel.setFont(new Font("Serif", Font.BOLD, 70));
		timerLabel.setText("19");
		timerPanel.add(timerLabel);
		timerPanel.setVisible(false);

		return timerPanel;
	}

	public Component createTimerTitle2() {

		timerTitle2.setSize(156, 145);
		timerTitle2.setLocation(39, 624);
		timerTitle2.setBackground(Color.white);

		JLabel picLabel = new JLabel(new ImageIcon(startShoe));
		timerTitle2.add(picLabel);

		timerTitle2.setVisible(false);

		return timerTitle2;
	}

	public Component createTimerPanel2() {

		// Create timer panel (don't make visible until winner is declared)
		timerPanel2 = new JPanel();
		timerLabel2 = new JLabel();
		timerPanel2.setSize(50, 52);
		timerPanel2.setLocation(91, 669);
		timerPanel2.setBackground(Color.white);

		timerLabel2.setFont(new Font("Serif", Font.BOLD, 60));
		timerPanel2.add(timerLabel2);
		timerPanel2.setVisible(false);

		return timerPanel2;
	}

	public Component createAddingUsersPanel() {

		addingUsers.setSize(220, 105);
		addingUsers.setLocation(1050, 634);
		addingUsers.setBackground(Color.white);

		JLabel picLabel = new JLabel(new ImageIcon(addUser));
		addingUsers.add(picLabel);

		addingUsers.setVisible(false);

		return addingUsers;
	}

	// Draw background to panel here...
	public void paint(Graphics g) {

		// **LINE UP HORSES EVENLY BEFORE RACE STARTS**
		update(g);
	}

	public void update(Graphics g) {

		// initialize dimensions for painting
		Dimension d = getSize();
		int w = horses[0].getWidth(this);
		int h = horses[0].getHeight(this);
		int width = track1.getWidth(this);

		// check if there was a winner, if so, we need to wait 10 seconds before
		// resetting game
		if (this.waiting) {
			try {
				if (timeCount > 0) // FIXED TIMER ISSUE!
					Thread.sleep(1250);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			timeCount--;
			timerLabel.setText("" + timeCount);
			// if(timeCount < 1) {
			// this.addingUsers.setVisible(true);
			// this.timerPanel.setVisible(false);
			// }
			if (timeCount < 0) {
				try {
					this.timerPanel.setVisible(false);
					Thread.sleep(1250);
				} catch (InterruptedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				try {
					resetGame();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				waiting = false;
			}
		} else { // if no winner, proceed

			super.paint(g);
			Graphics2D g2d = (Graphics2D) g;

			// Check if this game just started. If it did, wait 10 seconds
			// before launching horses...
			if (this.newGame) {
				timerPanel2.setVisible(true);
				timerTitle2.setVisible(true);

				g2d.drawImage(this.track1, 0, 0, this);
				for (int i = 0; i < this.maxPlayers; i++) {
					g.drawImage(horses[i], 0,
							(d.height - 135 - (this.maxPlayers - i) * 210
									/ this.maxPlayers), this);
				}
				try {
					if (timeCount > 0) // FIXED TIMER ISSUE!
						Thread.sleep(1250);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				timeCount--;
				timerLabel2.setText("" + timeCount);
				if (timeCount < 0) {
					try {
						Thread.sleep(1250);
					} catch (InterruptedException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					try {
						// start();
						this.timeCount = 21;
						this.newGame = false;
						timerPanel2.setVisible(false);
						timerTitle2.setVisible(false);
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			} else { // if neither timer is true, the race is on...
	
				// generate random speeds...
				regenRand();

				// give coordinates of where to paint the background
				if ((width > 0) && !this.newGame) {
					for (int j = 10, x = 0; j < 976; j += 100, x += (5500)) {
						if (j == 10)
							g2d.drawImage(this.track1,
									((-frameNumber * (speed * 3))), 0, this);
						g2d.drawImage(this.track1,
								((x) + (-frameNumber * (speed * 6))), 0, this);

//						System.out.println("fN = " + frameNumber);
					}
				}

				// Draw the finish line based on frameNumber (line gets darker
				// the further along the race gets)
				g2d.drawImage(this.finishLine1, 1104, 0, this);
				if (frameNumber > 50)
					g2d.drawImage(this.finishLine2, 1104, 0, this);
				if (frameNumber > 100)
					g2d.drawImage(this.finishLine3, 1104, 0, this);
				if (frameNumber > 160)
					g2d.drawImage(this.finishLine4, 1104, 0, this);
				if (frameNumber > 200)
					g2d.drawImage(this.finishLine5, 1104, 0, this);

				// If we've loaded the moving image, draw it.
				if ((w > 0) && (h > 0) && frameNumber != 0 && !this.newGame) {
					// redraws the horses across the screen
					for (int i = 0; i < this.maxPlayers; i++) {
						g.drawImage(
								horses[i],
								(100 + ((frameNumber + rands[i]) % (w + d.width)) - w),
								(d.height - 135 - (this.maxPlayers - i) * 210
										/ this.maxPlayers), this);
					}
				}

				// check for winner
				win = checkWinner();
				if (win > 0) {
					winnerPanel.add(wBust[win - 1]);
					winnerPanel.setLocation(335, 623);
					infoPanel.setLocation(500, 653);
					trophyPanel.setLocation(820, 633);

					winnerPanel.setVisible(true);
					infoPanel.setVisible(true);
					trophyPanel.setVisible(true);

					userPosition[win - 1].setLocation(378, 740);
					userPanels[win - 1].setLocation(500, 690);

					for (int i = 0; i < this.maxPlayers; i++) {
						if (i != (win - 1)) {
							userPanels[i].setVisible(false);
							userPosition[i].setVisible(false);
						}
					}

					// if we have a winner, tell winner timer to wait
					timerPanel.setVisible(true);
					timerTitle.setVisible(true);
					this.waiting = true;
				}
			}
		}
	}

	private void regenRand() {
		int bonus, userBonus = 0;
		Random randomGenerator = new Random();

		// generating random numbers
		for (int i = 0; i < this.maxPlayers; i++) {

			// userBonus = Integer.parseInt( userID ); // Possible userID bonus?

			bonus = (i == energyHorse) ? (speed / 2) : userBonus;
			bonus = (i == lastSecond) ? ((frameNumber < 100) ? (-speed / 3)
					: (frameNumber / (speed))) : bonus;
			bonus = (i == minorLucky) ? (frameNumber / (speed * 5)) : bonus;
			bonus = (i == lucky) ? (frameNumber / (speed * 3)) : bonus;
			rands[i] = rands[i]
					+ randomGenerator.nextInt(speed + bonus + userBonus);

//			if (jeffMagic)
//				rands[jM] = rands[jM]
//						+ randomGenerator.nextInt(speed + speed * 2 + userBonus);
		}
	}

	// Check for winners via location on screen
	public int checkWinner() {
		int w = bgW - 147;
		int highvalue = -1;
		int highplayer = 0;
		for (int i = 0; i < this.maxPlayers; i++) {
			if (frameNumber + rands[i] > w
					&& frameNumber + rands[i] > highvalue) {
				highplayer = i + 1;
				highvalue = frameNumber + rands[i];
			}
		}
		return highplayer;
	}
	
	public void playS() {
			SongPlayer s = new SongPlayer();
			String play = System.getProperty("user.dir") + "/soundFiles/herd.wav";

			s.playSong(play);
	}
}
